<template>
  <div style="width:100%;">
    <div class="query-form">
      <el-form ref="queryForm" :inline="true" :model="data_query_form">
        <el-form-item label="产品编码：" prop="productCode">
          <el-input v-model="data_query_form.productCode" type="text" placeholder="产品编码" />
        </el-form-item>
        <el-form-item label="产品名称(中)：" prop="productName">
          <el-input v-model="data_query_form.productName" type="text" placeholder="产品名称(中)" />
        </el-form-item>
        <el-form-item label="产品线：" prop="productLineCode">
          <el-select :disabled="true" v-model="data_query_form.productLineCode" placeholder="产品线">
            <el-option
              v-for="item in prodLineOps"
              :key="item.productLineCode"
              :label="item.productLineName"
              :value="item.productLineCode"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button @click="queryFormReset">重置</el-button>
          <el-button type="primary" @click="queryFormQuery">查询</el-button>
        </el-form-item>
      </el-form>
    </div>
    <!-- <div class="header-info" style="margin-top:40px;">
      <p>
        <span style="color:red;margin-left:20px;">注：可退量=库存量 - 占用量</span>
      </p>
    </div> -->
    <div class="product-list">
      <el-editable
        ref="productsList"
        v-loading="productTableLoading"
        height="400"
        :need-pagination="true"
        :columns="data_product_list.columns"
        :payload="data_product_list.data"
        :static-store="store"
        @reload="reloadData"
        @select="curSelect"
        @select-all="onSelectAll"
      />
    </div>
  </div>
</template>

<script>
import ElEditable from '@components/el-editable';
import { SALES_PRODUCTS_COLUMNS } from './product.const.js';
import { addProductList } from '@api/m_mall_web_v1.js';
import { isObject, compact, uniqBy } from 'lodash';
export default {
  name: 'ProductAddDialogProductListComponent',
  components: { ElEditable },
  props: {
    type: {
      type: String,
      default: 'default'
    },
    query: {
      type: Object,
      default: function() {
        return {};
      }
    },
    fetcher: {
      type: Function,
      default: function() {}
    },
    store: null
  },
  data() {
    return {
      data_query_form: {
        productCode: '',
        productName: '',
        productLineCode: ''
      },
      prodLineOps: [],
      data_product_list: {
        storageProducts: [],
        data: {},
        columns: SALES_PRODUCTS_COLUMNS
      },
      page: 1,
      selectedProducts: [],
      productTableLoading: false
    };
  },
  created() {
    this.setInitDataAndGetFirstData();
  },
  methods: {
    // 初始化搜索条件并请求初始化接口数据
    setInitDataAndGetFirstData() {
      // 这里唯一要做的数据初始化，是设置产品线的数据。
      // “||”的作用是因为数据结构在新建和编辑时候的不统一，所以就这样简便处理了
      // 理论上将，应该统一输入的数据结构
      this.prodLineOps.push({
        productLineCode: this.query.formData?.contract_data?.productLineCode || this.query.formData.productLineCode,
        productLineName: this.query.formData?.contract_data?.productLineName || this.query.formData.productLineName
      });
      // 写死产品线搜索条件的值
      //
      this.data_query_form.productLineCode =
        this.query.formData?.contract_data?.productLineCode || this.query.formData.productLineCode;
      this.reloadData({ number: 1, size: 20 });
    },
    reloadData(pager) {
      // 切换分页时，存储数据
      this.productTableLoading = true;
      this.page = pager.number;
      this.fetcher({
        url: addProductList,
        method: 'post',
        data: {
          busModel: this.query.formData.contract_data.busModel || this.query.formData.contract_data.businessModelCode,
          page: pager.number,
          pageSize: pager.size,
          productCode: this.data_query_form.productCode,
          productLineCode: this.data_query_form.productLineCode,
          productName: this.data_query_form.productName,
          returnProductList: this.query.formData.return_goods.map(item => item.productName),
          vendorNum: this.query.formData.supplier_id || this.query.formData.supplier_data.vendorCode,
          marketCode: this.query.formData.contract_data.channelType || this.query.formData.contract_data.marketCode
        }
      })
        .then(res => {
          let result = isObject(res.data.payload) ? res.data.payload : [];
          this.data_product_list.data = result;
          this.data_product_list.data.content = this.data_product_list.data.content.map(item => {
            return {
              mixsIds: item.productCode,
              productCount: 1,
              ...item,
              isChecked: false // isChecked作为选中标示即可
            };
          });
          // 为数据绑定“可选量”及“已选量”，统计的纬度是“产品名”即productName
          this.setInitialProductsDataNums();
          if (this.data_product_list.storageProducts.length > 0) {
            this.reActiveListRows();
          }
        })
        .finally(() => {
          this.productTableLoading = false;
        });
    },
    //
    setInitialProductsDataNums() {
      let exProductNamesNum = this.concatCommonNameProduct(this.query.formData.exchange_goods, 'productCount');
      let returnGoodsCurNums = this.concatCommonNameProduct(this.query.formData.return_goods, 'productCount');
      // 初始化可选数量
      returnGoodsCurNums.forEach(rGood => {
        this.data_product_list.data.content.forEach(item => {
          if (item.productName === rGood.name) {
            this.$set(item, 'optionalQuantity', rGood.commonNameTotalNum);
          }
        });
      });
      // 初始化已选数量
      this.data_product_list.data.content.forEach(item => {
        this.$set(item, 'selectedQuantity', 0);
        exProductNamesNum.forEach(exGood => {
          if (item.productName === exGood.name) {
            this.$set(item, 'selectedQuantity', exGood.commonNameTotalNum);
          }
        });
      });
    },
    reActiveListRows() {
      let curPageRow = this.data_product_list.storageProducts;
      if (curPageRow && curPageRow.length > 0) {
        curPageRow.forEach(item => {
          let findItem = this.data_product_list.data.content.find(it => {
            return it.mixsIds === item.mixsIds;
          });
          if (findItem) {
            this.$nextTick(() => {
              this.$refs.productsList.$refs.table.toggleRowSelection(findItem, true);
            });
            findItem.isChecked = true;
          }
        });
      }
    },
    queryFormReset() {
      this.$refs['queryForm'].resetFields();
      this.queryFormQuery();
    },
    queryFormQuery() {
      this.reloadData({ number: 1, size: 20 });
    },
    deDuplication(curSelectedProducts) {
      this.data_product_list.storageProducts = this.data_product_list.storageProducts.concat(curSelectedProducts);
      this.data_product_list.storageProducts = this.uniqueDoubleCycle(
        this.data_product_list.storageProducts,
        'mixsIds'
      );
      return this.data_product_list.storageProducts;
    },
    concatCommonNameProduct(products, numKey) {
      console.log(this.query, 'this.query');
      if (!products.length) return [];
      // 第一步，通过退货产品，计算出，同名产品的总“退货量”
      // 先获取到去重后的产品名称有哪些
      let uniqProductsNames = uniqBy(products, 'productName').map(item => item.productName);
      // 然后，我们形成一个下面这样结构的数组，记录上一步已选同名产品的总“退货量”
      let curProductNameTotalNumsArr = [];
      uniqProductsNames.forEach(name => {
        let obj = {
          name: '',
          commonNameTotalNum: 0
        };
        products.forEach(item => {
          obj.name = name;
          if (name === item.productName) {
            obj.commonNameTotalNum += item[numKey];
          }
        });
        curProductNameTotalNumsArr.push(obj);
      });
      return curProductNameTotalNumsArr;
    },
    onSelectAll(selection) {
      // 无论是否选中数据，只要存在flag判断的条件，就进行数据清空并选中之前已选中的数据，模拟“无效感”。
      // 只要存在同名总量大于可换总量的时候，就"禁止"全选并提示,
      // 要分别计算当前数据的同名数量和已选退货的同名数量来做对比
      let rGoods = this.concatCommonNameProduct(this.query.formData.return_goods, 'productCount');
      let curListGoods = this.concatCommonNameProduct(selection, 'productCount');
      let exGoods = this.concatCommonNameProduct(this.query.formData.exchange_goods, 'productCount');
      let hahaArr = [];
      rGoods.forEach(r => {
        let obj = {
          name: '',
          rNum: 0,
          eNum: 0
        };
        obj.name = r.name;
        obj.rNum = r.commonNameTotalNum;
        // 先把选中的赋值
        curListGoods.forEach(curGoods => {
          if (r.name === curGoods.name) {
            obj.eNum = curGoods.commonNameTotalNum;
          }
        });
        // 再加上已有的exchange_goods列表
        exGoods.forEach(exG => {
          if (r.name === exG.name) {
            obj.eNum += exG.commonNameTotalNum;
          }
        });
        hahaArr.push(obj);
      });

      let flag = hahaArr.some(item => {
        return item.eNum > item.rNum;
      });
      if (flag) {
        this.$refs.productsList.$refs.table.clearSelection();
        this.data_product_list.data.content.forEach(item => {
          if (item.isChecked) {
            this.$refs.productsList.$refs.table.toggleRowSelection(item, true);
          }
        });
        this.$message({
          type: 'warning',
          message: '全选数量大于已选退货数据量，请手动点选！',
          duration: 4000
        });
        return;
      }
      // 如果有数据，说明是全选选中状态，那么把所有的数据放入storageProducts并去重
      if (selection.length) {
        this.data_product_list.storageProducts = this.deDuplication(
          this.data_product_list.storageProducts.concat(this.data_product_list.data.content)
        );
        this.data_product_list.storageProducts.forEach(item => {
          item.isChecked = true;
        });
      } else {
        // 如果没数据，就把当前页this.data_product_list.data的数据从storageProducts挨个删除
        // 即从存储的产品池中，删除当前已取消的产品（因为是全选操作，所以已取消的产品，即当页所有产品）
        this.data_product_list.storageProducts.forEach((item, index) => {
          let findItem = this.data_product_list.data.content.find(it => {
            return it.mixsIds === item.mixsIds;
          });
          if (findItem) {
            // 猜猜这里为啥用undefined占位？
            // 因为如果删除了位置后，下标就变了，这里以下标作为标识
            this.data_product_list.storageProducts.splice(index, 1, undefined);
          }
        });
      }
      // 数组去空
      this.data_product_list.storageProducts = compact(this.data_product_list.storageProducts);
      // 因为全选的时候，我拿的是所有列表的数据，这里手动把returnCount小于等于0的数据删掉
      // 个人觉得这样的逻辑不太好，这里由于项目已经基本完善，改动很大，暂时这样处理吧
      this.data_product_list.storageProducts = this.data_product_list.storageProducts.filter(item => {
        // 其实这里，前面的逻辑已经return掉了，所以这里没什么用，作为二次的保险吧。
        return item.isChecked;
      });

      // 全选后计算最终的结果数据，给selectedQuantity赋值
      let uniqStorageArr = this.concatCommonNameProduct(this.data_product_list.storageProducts, 'productCount');
      uniqStorageArr.forEach(it => {
        this.data_product_list.storageProducts.forEach(item => {
          if (it.name === item.productName) {
            item.selectedQuantity = it.commonNameTotalNum;
          }
        });
      });
      this.$emit('selectionChange', this.data_product_list.storageProducts);
    },
    curSelect(selection, row) {
      // 这逻辑判断，有点2了，这样吧。。不改了
      // 判断当前是选中还是取消,true是选中，false是取消
      // 也即selection中是否存在row，存在就是选中，不存在就是取消选中
      let flag;
      flag =
        selection.findIndex(item => {
          return item.mixsIds === row.mixsIds;
        }) !== -1;
      // 是否存在于相应的数据中
      // 判断当前选中或取消选中的数据是否已存在于storage暂存数组中。
      let storageIdx = this.data_product_list.storageProducts.findIndex(item => {
        return item.mixsIds === row.mixsIds;
      });
      if (flag) {
        row.isChecked = true;
        // 选中一个，那么要给所有同名数据的可选量字段 +1
        this.data_product_list.data.content.forEach(item => {
          if (item.productName === row.productName) {
            item.selectedQuantity += 1;
          }
        });
        // 因为是单选，所以这里的selection只有一个
        // 如果是增加，就一股脑把当前所有选中的selection都放进storageProducts，然后再去重
        this.data_product_list.storageProducts = this.deDuplication(
          this.data_product_list.storageProducts.concat(selection)
        );
      } else {
        row.isChecked = false;
        // 如果是减少，那么直接删除在storageProducts中对应下标的数据
        // 取消选中一个，那么要给所有同名数据的可选量字段 -1
        this.data_product_list.data.content.forEach(item => {
          if (item.productName === row.productName) {
            item.selectedQuantity -= 1;
          }
        });
        this.data_product_list.storageProducts.splice(storageIdx, 1);
      }
      this.$emit('selectionChange', this.data_product_list.storageProducts);
    },
    // 去重算法
    uniqueDoubleCycle(array, key) {
      let newArr = [];
      let len = array.length;
      let isRepeat;

      for (let i = 0; i < len; i++) {
        // 第一次循环
        isRepeat = false;
        for (let j = i + 1; j < len; j++) {
          // 第二次循环
          if (array[i][key] === array[j][key]) {
            isRepeat = true;
            break;
          }
        }
        if (!isRepeat) {
          newArr.push(array[i]);
        }
      }
      return newArr;
    }
  }
};
</script>

<style lang="less" scoped>
.product-list {
  display: flex;
  flex: 1;
  .pagination {
    text-align: right;
    margin-top: 20px;
  }
}
</style>
